Galileo Computing < openbook > Galileo Computing - Professionelle Bücher. Auch für Einsteiger.

...powered by www.netzwerkartist.de...

 << zurück
Visual C# 2005 von Andreas Kühnel
Das umfassende Handbuch
Buch: Visual C# 2005

Visual C# 2005
1.320 S., mit 2 CDs, 59,90 Euro
Galileo Computing
ISBN 3-89842-586-X
gp Kapitel 22 Grafische Programmierung mit GDI+
  gp 22.1 Die Namespaces der GDI+-Schnittstelle
  gp 22.2 Die Klasse »Graphics«
    gp 22.2.1 Überblick über die Klasse »Graphics«
    gp 22.2.2 Sich die Referenz auf das »Graphics«-Objekt besorgen
    gp 22.2.3 Das Neuzeichnen einer Grafik mit »ResizeRedraw« und »Invalidate«
    gp 22.2.4 Zerstören von grafischen Objekten (Dispose)
    gp 22.2.5 Das Koordinatensystem von GDI+
    gp 22.2.6 Festlegen eines anderen Ursprungspunkts
    gp 22.2.7 Die grafischen Methoden der Klasse »Graphics«
    gp 22.2.8 Eine Linie zeichnen
    gp 22.2.9 Mehrere Linien zeichnen
    gp 22.2.10 Rechtecke zeichnen
    gp 22.2.11 Punkte zeichnen
    gp 22.2.12 Polygone zeichnen
    gp 22.2.13 Ellipsen, Ellipsenbogen und Ellipsensegment
    gp 22.2.14 Kurvenzüge
    gp 22.2.15 Bézierkurven
  gp 22.3 Elementare Klassen für grafische Operationen
    gp 22.3.1 Die Klasse »Brush«
    gp 22.3.2 Die Klasse »Pen«
    gp 22.3.3 Farbeinstellungen mit »Color«
  gp 22.4 Die Schriftdarstellung
    gp 22.4.1 Allgemeines
    gp 22.4.2 Die Klassen »Font« und »FontFamily«
    gp 22.4.3 Der Schriftstil mit »FontStyle«
    gp 22.4.4 Die grafische Ausgabe einer Zeichenfolge
    gp 22.4.5 Die Abmessungen mit »MeasureString« ermitteln
    gp 22.4.6 Die Klasse »StringFormat«
  gp 22.5 Bilddateien
    gp 22.5.1 Bilder und Grafiken der .NET-Klassenbibliothek
    gp 22.5.2 Die Bitmap-Dateiformate
    gp 22.5.3 Bilder mit der Klasse »Image«
    gp 22.5.4 Bitmaps


Galileo Computing

22.3 Elementare Klassen für grafische Operationedowntop

Als ich Ihnen die Zeichenmethoden von Graphics vorgestellt habe, mussten wir den DrawXxx-Methoden ein Pen-Objekt und den FillXxx-Methoden ein Brush-Objekt übergeben. Es wird Zeit, dass wir uns nun etwas näher mit diesen beiden Typen auseinander setzen.

Der englische Begriff »Pen« bedeutet ins Deutsche übersetzt Stift, »Brush« kann mit Pinsel übersetzt werden. Sie können diese Begriffe auch auf die Funktionalität der Typen abbilden: Mit einem Stift werden Striche gezeichnet, mit einem Pinsel großflächig Farben aufgetragen.


Galileo Computing

22.3.1 Die Klasse »Brush«  downtop

Ein Objekt vom Typ Brush dient dazu, ein grafisches Objekt mit einer Farbe oder sogar einem Muster zu füllen. Allerdings ist Brush abstrakt definiert, was zur Folge hat, dass die Klasse nicht instanziiert werden kann. Dafür werden aber fünf abgeleitete Klassen bereitgestellt, die jeweils einem bestimmten Einsatzzweck dienen:

gp  System.Drawing.SolidBrush
gp  System.Drawing.Drawing2D.HatchBrush
gp  System.Drawing.TextureBrush
gp  System.Drawing.Drawing2D.LinearGradienBrush
gp  System.Drawing.Drawing2D.PathGradientBrush

Brush gehört dem Namespace System.Drawing an, drei der abgeleiteten Klassen sind jedoch Mitglieder von System.Drawing.Drawing2D.

Die Klasse »SolidBrush«

Fangen wir mit der einfachsten Klasse an, die wir in den vorhergehenden Beispielen auch schon benutzt haben. SolidBrush hat nur einen Konstruktor, dem die Füllfarbe des grafischen Objekts vom Typ Color übergeben wird. Mit


e.Graphics.FillEllipse(new SolidBrush(Color.Blue), 0, 0, 100, 200);

zeichnen Sie zum Beispiel eine blau gefüllte Ellipse. Sie haben allerdings auch noch eine andere Möglichkeit, bei der Sie kein Brush-Objekt erzeugen müssen. Dazu übergeben Sie eine vordefinierte Konstante der Klasse Brushes:


e.Graphics.FillEllipse(Brushes.Blue, 0, 0, 100, 200);

Die Konstantenbezeichner entsprechen den der in der Klasse Color vordefinierten Farben.

Füllmuster mit »HatchBrush«

Mit SolidBrush wird ein Grafikobjekt gleichmäßig mit einer Farbe gefüllt. Das sieht auf einem Bildschirm sehr gut aus, kann aber bei der Ausgabe auf einem Schwarz-Weiß-Drucker zu Problemen bei der Objekterkennung führen. In solchen Fällen ist es oft besser, die Grafikobjekte mit einem Muster, beispielsweise einer Schraffur, zu füllen. HashBrush kann das.

Eine mit einer Schraffur gefüllte Fläche ist durch drei Charakteristika gekennzeichnet: die Vordergrundfarbe, die Hintergrundfarbe und das Schraffurmuster. Diese Eigenschaften spiegeln sich auch in den beiden Konstruktoren der Klasse HatchBrush wider.


public HatchBrush(HatchStyle, Color foreColor);
public HatchBrush(HatchStyle hatchstyle, Color foreColor, Color backColor);

Dem zuerst aufgeführtem Konstruktor fehlt die Übergabe der Hintergrundfarbe. Das ist natürlich kein Fehler, diese ist standardmäßig auf Schwarz festgelegt.

Aus den Parametern des dreiparametrigen Konstruktors kann geschlossen werden, dass sich ein HatchBrush-Objekt durch drei Eigenschaften auszeichnet:

gp  HatchStyle
gp  ForegroundColor
gp  BackgroundColor

Die beiden Farbeigenschaften sind vom Typ Color, HatchStyle ist vom Typ der gleichnamigen Enumeration, die vordefinierte Schraffurstile enthält.

Die Mitglieder der HatchStyle-Enumeration hier einzeln aufzuführen, würde zu weit führen. Stattdessen wollen wir uns alle Schraffurstile in einem Fenster in Rechtecken anzeigen lassen.


// --------------------------------------------------------------
// Beispiel: ...\Kapitel 22\HatchBrush-Muster
// --------------------------------------------------------------
private void Form1_Paint(object sender, PaintEventArgs e) {
  Graphics g = e.Graphics;
  int b = 0, h = 0, i = 0;
  HatchBrush hBrush;
  // die Enumeration 'HatchStyle' durchlaufen und alle
  // Mitglieder auswerten
  foreach(HatchStyle hs in Enum.GetValues(typeof(HatchStyle))) {
    b = 10 + (i % 6) * 80;
    h = (int)(i / 6) * 50;
    hBrush = new HatchBrush(hs, Color.Black, Color.White);
    g.FillRectangle(hBrush, b, h + 15, 70, 40);
    i++;
    hBrush.Dispose();
  }
}

Um auf alle Mitglieder der Enumeration HatchStyle zugreifen zu können, rufen wir die statische Methode GetValues der Klasse Enum auf. Übergeben müssen wir dem Methodenaufruf den Typ Type von HatchStyle, den uns das Schlüsselwort typeof liefert.

Wenn der Clientbereich einer Form oder Picturebox mit einem Schraffurmuster gefüllt wird, wird das Muster einfach periodisch in horizontaler und vertikaler Richtung wiederholt. Der Ursprung der Muster entspricht dabei dem Ursprung des Graphics-Objekts und ist damit auch der Ursprung des Clientbereichs.

Abbildung
Hier klicken, um das Bild zu vergrößern

Abbildung 22.12   Die »HatchBrush«-Muster

Die Eigenschaft RenderingOrigin des Graphics-Objekts bietet die Möglichkeit, den Ursprungspunkt der Schraffuren nach eigenem Ermessen festzulegen, z.B.:


e.Graphics.RenderingOrigin(25, 69);

Es stellt sich jetzt die Frage, welchen Vorteil wir aus der Eigenschaft RenderingOrigin ziehen können. Betrachten Sie dazu den folgenden Code, der zu der in Abbildung 22.13 gezeigten Form führt.


private void Form1_Paint(object sender, PaintEventArgs e) {
  Graphics g = e.Graphics;
  HatchBrush tb = new HatchBrush(HatchStyle.Plaid, Color.White);
  for (int i = 0; i <= 3; i++) {
    g.FillRectangle(tb, 30 * i, 20 * i, 80, 50);
  }
}

Abbildung
Hier klicken, um das Bild zu vergrößern

Abbildung 22.13   Füllmuster mit fließendem Übergang

Wir sehen, dass die Füllmuster fließend ineinander übergehen. Die Überlappung der vier Rechtecke ist nicht erkennbar. Ergänzen wir nun die for-Schleife mit der RenderingOrigin-Eigenschaft wie folgt:


...
for (int k = 0; k <= 3; k++) {
  g.RenderingOrigin = new Point(30 * i, 20 * i); 
  g.FillRectangle(tb, 30 * i, 20 * i, 80, 50);
}

Nun sind die Auswirkungen ganz offensichtlich: Die Rechtecke überlappen sich, weil sich das Füllmuster nicht mehr kontinuierlich über die Graphics-Fläche spannt.

Abbildung
Hier klicken, um das Bild zu vergrößern

Abbildung 22.14   Füllmuster, festgelegt mit »RenderingOrigin«

Benutzerdefinierte Schraffuren mit »TextureBrush«

Vielleicht reichen Ihnen die vordefinierten Füllmuster der Enumeration HatchStyle nicht aus, oder Sie können Ihrem kreativen Schaffensdrang nicht Einhalt gebieten und wollen eigene Muster zur Füllung aller mit den FillXxx-Methoden gezeichneten Grafikobjekte verwenden. Dann müssen Sie den grafischen Methoden ein Objekt vom Typ TextureBrush übergeben.

TextureBrush definiert eine Reihe von Konstruktoren. Dem einfachsten übergeben Sie bei der Instanziierung die Referenz auf ein Image-Objekt:


public TextureBrush(Image image);

Image ist eine abstrakte Klasse, aus der die beiden Klassen Bitmap und Metafile abgeleitet werden.

Angenommen Sie hätten eine eigene Bitmap gezeichnet und es in dem Ordner gespeichert, der die ausführbare Datei der Anwendung enthält. Dann könnten Sie sich unter Aufruf der statischen Methode FromFile die Referenz auf die Datei besorgen und diese dem Konstruktor übergeben:


Graphics g = e.Graphics;
TextureBrush tb = new TextureBrush(Image.FromFile("Bitmap1.bmp"));
g.FillRectangle(tb, 0, 0, this.ClientSize.Width, this.ClientSize.Height);

Mit diesem Programmcode wird die durch das Graphics-Objekt beschriebene Zeichenfläche ausgehend vom Koordinatenursprung (0, 0) mit der Bitmap gefüllt. Das könnte beispielsweise wie in der folgenden Abbildung gezeigt aussehen. Die Bitmap hat dabei eine Größe von 50 x 50 Pixel.

Abbildung
Hier klicken, um das Bild zu vergrößern

Abbildung 22.15   Füllmuster, festgelegt mit »TextureBrush«

Nehmen wir jetzt an, das zu füllende Rechteck hätte seinen eigenen Ursprung bezüglich seiner Clientfläche nicht im Punkt (0, 0), sondern in (25, 25). Die Breite des Rechtecks sei 215 Pixel, seine Höhe 100 Pixel:


...
g.FillRectangle(tb, 25, 25, 215, 100);

Die Positionierung der Bitmaps auf der Zeichenfläche ist standardmäßig an das Graphics-Objekt und dessen Ursprung gebunden, der immer in (0, 0) des zugrunde liegenden Clientbereichs liegt.

Ein zu zeichnendes Rechteck kann man sich wie ein Fenster auf der Zeichenfläche vorstellen, das nur einen Teilausschnitt sichtbar macht. Weil sich aber die Füllmuster nicht an den Ursprungskoordinaten des Rechtecks, sondern weiterhin am Ursprung der Zeichenfläche orientieren, werden wir die Form wie in der folgenden Abbildung gezeigt sehen.

Abbildung
Hier klicken, um das Bild zu vergrößern

Abbildung 22.16   Mit »TextureBrush« verschobenes Füllmuster

Lineare Verläufe mit »LinearGradientBrush«

Kommen wir jetzt zur nächsten Brush-Klasse, die uns zu weiteren Farbspielereien geradezu ermutigt: LinearGradientBrush. Vielleicht sehen wir uns gleich zu Anfang ein Beispiel an, das auf dieser Klasse basiert.

Abbildung
Hier klicken, um das Bild zu vergrößern

Abbildung 22.17   Farbverlauf mit »LinearGradientBrush«

Wir sehen einen Farbverlauf, der sich von Weiß kontinuierlich nach Schwarz fortsetzt. Dies ist das Resultat der Klasse LinearGradientBrush. Der Programmcode, der dieser Abbildung zugrunde liegt, ist wie folgt:


LinearGradientBrush linearBrush = new LinearGradientBrush(
                                         new Point(0, 150),
                                         new Point(300, 150),
                                         Color.White,
                                         Color.Black);
e.Graphics.FillRectangle(linearBrush, 0, 0, 300, 150);

Wie Sie unschwer erkennen können, sind nur zwei Zeilen Code notwendig.

Wenden wir uns nun, nachdem Sie wissen, wozu die Klasse dient, den Details zu. LinearGradientBrush definiert insgesamt acht Konstruktoren. Im Codefragment oben wurde der folgende benutzt:


public LinearGradientBrush(Point point1, Point point2,
                           Color color1, Color color2);

Die Definition des Farbverlaufs setzt zwei Punkte voraus: den Startpunkt des Farbverlaufs (point1) und den Endpunkt (point2). Beiden Punkten ist eine Farbe zugeordnet: dem Punkt point1 die Farbe color1, dem Punkt point2 die Farbe color2. Zwischen diesen beiden Punkten verläuft die Farbe von color1 kontinuierlich nach color2.

Die Frage, ob der Farbverlauf horizontal oder vertikal orientiert ist, hängt von der Festlegung der beiden Punkte ab. Stellen Sie sich dazu eine Verbindungslinie zwischen point1 und point2 vor. Senkrecht zu dieser werden die farbgleichen Pixelbalken gezeichnet. Daraus folgt, dass für den Fall, dass die Verbindungslinie horizontal ist, der Farbverlauf vertikal gezeichnet wird, bei einer vertikalen Verbindungslinie der Farbverlauf horizontal dargestellt wird. Selbstverständlich können Farbverläufe auch winklig im Raum stehen.

Abbildung
Hier klicken, um das Bild zu vergrößern

Abbildung 22.18   Definition der Farbverläufe

Die Klasse »PathGradientBrush«

Wollen Sie wissen, wie man die in der folgenden Abbildung gezeigte, ziemlich beeindruckende Figur programmiert?

Abbildung
Hier klicken, um das Bild zu vergrößern

Abbildung 22.19   Beispiel für die Klasse »PathGradientBrush«

Eigentlich ist es kaum zu fassen, aber tatsächlich genügen dazu nur drei Zeilen Programmcode:


Point[] pt = new Point[]{new Point(30, 30), 
                         new Point(0, 200), 
                         new Point(300, 200), 
                         new Point(140, 160),
                         new Point(200, 0)};
PathGradientBrush p = new PathGradientBrush(pt);
e.Graphics.FillRectangle(p, 0, 0, 300, 300);

Wenn Sie nicht vor ausgesprochen langen Codezeilen zurückschrecken, können Sie den Code sogar auf eine Zeile reduzieren!

Basis ist die fünfte und letzte Klasse, die aus der Basisklasse Brush abgeleitet wird: PathGradientBrush. Ich habe im Codefragment den Konstruktor gewählt, der ein Point-Array entgegennimmt. Aus dem Point-Array wird ein Polygon gebildet und dieses mit den Standardfarben gefüllt.

PathGradientBrush ist die allgemeinste aller Brush-Klassen, die Verläufe zwischen Punktpaaren erzeugt. Wollen Sie die Farben selbst bestimmen, übergeben Sie einfach den gewünschten Farbwert an die Eigenschaften CenterColor und/oder SurroundColor. Letztere nimmt sogar ein Color-Array entgegen, um mehrere Randfarben der Figur festzulegen. Mit der Eigenschaft CenterPoint lässt sich der Mittelpunkt des Polygons individuell festlegen. Er darf sogar außerhalb der zu zeichnenden Figur liegen.

Im nächsten Codefragment werden die Eigenschaften dazu benutzt, um einen Kreis als schräg angestrahlte Kugel erscheinen zu lassen.


private void Form1_Paint(object sender, PaintEventArgs e) {
  GraphicsPath graphPath = new GraphicsPath();
  graphPath.AddEllipse(20, 20, 170, 170);
  PathGradientBrush brush = new PathGradientBrush(graphPath);
  brush.CenterPoint = new Point(130, 130);
  brush.CenterColor = Color.White;
  brush.SurroundColors = new Color[]{Color.Green};
  e.Graphics.FillRectangle(brush, 0, 0, 300, 300);
}

Abbildung
Hier klicken, um das Bild zu vergrößern

Abbildung 22.20   Dreidimensional erscheinender Kreis, gezeichnet mit »PathGradientBrush«

In diesem Beispiel kommt ein anderer Konstruktor zum Einsatz, der ein Übergabeargument vom Typ GraphicsPath erwartet:


public PathGradientBrush(GraphicsPath);

GraphicsPath ist eine nicht ableitbare Klasse und repräsentiert eine Reihe verbundener Linien und Kurven, die über Methoden wie beispielsweise AddRectangle, AddLine usw. zu einer geometrischen Figur geformt werden. Im Code wurde die Methode AddEllipse dazu benutzt, einen Kreis festzulegen. Der Punkt, der die Position der inneren Farbe beschreibt, ist außerhalb der Mitte des Kreises festgelegt. Die innere Farbe ist Weiß, die Randfarbe Grün.


Galileo Computing

22.3.2 Die Klasse »Pen«  downtop

Die Klasse Pen ist einem Stift vergleichbar, der Linien in einem festgelegten Format zeichnet. Vier Konstruktoren stehen uns zur Verfügung, um diesen Zeichenstift zu realisieren.


public Pen(Brush);
public Pen(Color);
public Pen(Brush, float);
public Pen(Color, float);

Sie müssen also in jedem Fall eine Brush-Referenz oder mit Color einen Farbwert übergeben und können über die Übergabe eines zweiten Parameters auch die Strichbreite bestimmen.

Das Zeichnen unterschiedlicher Linienstile

Erzeugen Sie ein Pen-Objekt, wird standardmäßig eine durchgehende Linie gezeichnet. Das muss aber nicht so sein, denn mit der Eigenschaft DashStyle können wir das Linienmuster auch anderweitig festlegen:


public DashStyle DashStyle {get; set;}

Um zu wissen, welche Linienstile zur Auswahl stehen, müssen wir einen Blick in die DashStyle-Enumeration werfen.


Tabelle 22.3   Mitglieder der Enumeration »DashStyle«

DashStyle-Member Beschreibung
Solid Durchgezogene Linie
Dash Gestrichelte Linie
Dot Gepunktete Linie
DashDot Abwechselnd Strich-Punkt
DashDotDot Abwechselnd Strich-Punkt-Punkt
Custom Benutzerdefiniert

Die ersten fünf Konstanten sind trivial, die letzte, DashStyle.Custom, sollten wir uns noch etwas genauer ansehen.

Standardmäßig zeichnet die benutzerdefinierte Variante eine durchgezogene Linie. Nur wenn die Eigenschaft DashPattern einen Wert aufweist, der von null verschieden ist, wird die in DashPattern definierte Linie gezeichnet. Wir müssen uns deshalb zuerst diese Eigenschaft ansehen:


public float[] DashPattern {get; set;}

Im ersten Moment irritiert der Typ float-Array. Aber weil wir es mit einem Array zu tun haben, steht es uns frei, einen beliebigen Linienstil festzulegen. Dazu ein Beispiel:


Pen pen = new Pen(Color.Black);
pen.DashPattern = new float[]{4, 2, 6, 1};

Das erste Array-Element legt die Länge der ersten Linie fest, das zweite Array-Element die Länge des sich anschließenden Zwischenraums, das dritte Element die Länge der zweiten Linie, das vierte Element die Länge des darauf folgenden Zwischenraums usw. Es bleibt nur noch zu klären, was unter der Länge verstanden wird. Hierbei spielt die Linienbreite eine entscheidende Rolle, denn es gilt, dass die Länge jedes Striches und jedes Zwischenraums im Strichmuster das Produkt aus dem Wert des Array-Elements und der Breite des Pen-Objekts berechnet.

Das folgende Beispielprogramm zeigt in der Form alle Mitglieder der Enumeration DashStyle an. Für die Ausgabe des Bezeichners wird die Methode DrawString des Graphics-Objekts benutzt, der wir uns ab Abschnitt 22.4 noch zuwenden werden. Innerhalb der Schleife wird eine benutzerdefinierte Strich-Punkt-Linie definiert.


// --------------------------------------------------------------
// Beispiel: ...\Kapitel 22\DashStyles
// --------------------------------------------------------------
private void Form1_Paint(object sender, PaintEventArgs e) {
  int y = 0;
  Font font = new Font("Courier New", 12);
  Pen pen = new Pen(Color.Black, 2);
  // die Member der Enumeration 'DashStyle' durchlaufen
  foreach(DashStyle ds in Enum.GetValues(typeof(DashStyle))) {
    // Name des DashStyles ausgeben
    e.Graphics.DrawString(ds.ToString(), font, Brushes.Black, 10, y * 20);
    // aktuellen DashStyle dem Pen-Objekt zuweisen
    pen.DashStyle = ds;
    // benutzerdefinierten DashStyle festlegen (Strich-Punkt-Linie)
    if(ds == DashStyle.Custom) {
      pen.DashPattern = new float[]{10, 2, 2, 2};
    }
    // Linie zeichnen
    e.Graphics.DrawLine(pen, 130, 10 + y * 20, 300, 10 + y * 20);
    y++;
  }
}

Abbildung
Hier klicken, um das Bild zu vergrößern

Abbildung 22.21   Die Konstanten der Enumeration »DashStyle«

Linienverbindungen

Werden Linien, die eine größere Breite haben, mit der Methode DrawLines oder einer der Methoden, die einen Linienzug ergeben, gezeichnet, kann der Punkt, an dem die Linien zusammenstoßen, mit der Eigenschaft LineJoin festgelegt werden.


public LineJoin LineJoin {get; set;}

Standardmäßig laufen die beiden Linien spitz aufeinander zu. In der Enumeration LineJoin werden darüber hinaus noch Alternativen angeboten, den Verbindungspunkt abzuschrägen oder abzurunden.


Tabelle 22.4   Die Enumeration »LineJoin«

LineJoin-Member Beschreibung
Miter (Standard) Spitz zulaufende Verbindungslinien
Bevel Mit einer Diagonalen abgeflachte Verbindungslinien
Round Abgerundete Verbindungslinien
MiterClipped Ähnlich Miter, jedoch immer spitzer zulaufend

Das folgende Beispielprogramm soll den Effekt von LineJoin demonstrieren und je zwei Linien mit den unterschiedlichen Einstellungen ausgeben.


// --------------------------------------------------------------
// Beispiel: ...\Kapitel 22\Linienverbindung
// --------------------------------------------------------------
private void Form1_Paint(object sender, PaintEventArgs e) {
  Pen pen = new Pen(Brushes.Black, 30);
  int i = 0;
  foreach(LineJoin lj in Enum.GetValues(typeof(LineJoin))) {
    pen.LineJoin = lj;
    Point[] pt = new Point[]{new Point(i * 110 + 20, 30),
                             new Point(i * 110 + 100, 30), 
                             new Point(i * 110 + 100, 80)};
    e.Graphics.DrawLines(pen, pt);
    i++;
  }
}

Abbildung
Hier klicken, um das Bild zu vergrößern

Abbildung 22.22   Linienverbindung, angelegt mit »LineJoin«

Der Stil des Linienzugs

Die Eigenschaft LineJoin zeigt nur dann eine Wirkung, wenn die Linienbreite so groß gewählt wird, dass aus der Linie im Grunde genommen schon eine geometrische Figur wird. Wenn eine Linie mit der Eigenschaft DashStyle nicht mehr durchgezogen, sondern zum Beispiel gestrichelt gezeichnet wird, treten ähnliche Probleme auch innerhalb der Linie auf: Die einzelnen Elemente werden als Blöcke gezeichnet. Vielleicht wünschen Sie sich aber eine Rundung der Elemente oder eine Abschrägung, um die Optik zu verbessern. Dann müssen Sie die Eigenschaft DashCap des Pen-Objekts entsprechend einstellen.

DashCap basiert natürlich ebenfalls auf einer Enumeration, die drei Mitglieder bereitstellt.


Tabelle 22.5   Die Mitglieder der Enumeration »DashCap«

DashCap-Member Beschreibung
Flat (Standard) Das Ende des Linienelements ist abgeflacht.
Round Das Ende des Linienelements ist abgerundet.
Triangle Das Ende des Linienelements ist abgeschrägt.

In der folgenden Abbildung können Sie die Auswirkungen der verschiedenen Einstellungen anhand einer gestrichelten Linie sehen. Die Linie oben ist der Standard und zeigt die abgeflachten Enden, die in der mittleren Linie abgerundet sind. Die unterste Linie hat die Einstellung Triangle.

Abbildung
Hier klicken, um das Bild zu vergrößern

Abbildung 22.23   Die Auswirkung der Eigenschaft »DashCap«

Linienenden

In Abbildung 22.23 fällt auf, dass der Linienanfang davon nicht betroffen ist (und im Übrigen auch nicht das Linienende, das bei der mittleren und unteren Linie in den freien Zwischenraum fällt).

Um Linienanfang und Linienende festzulegen, bietet die Pen-Klasse zwei Eigenschaften an, die Gestaltungsmöglichkeiten über das Abrunden und Abschrägen hinaus offerieren: StartCap und EndCap.


public LineCap StartCap {get; set;}
public LineCap EndCap {get; set;}

LineCap gibt die Variationsmöglichkeiten vor und hat die folgenden Mitglieder:


Tabelle 22.6   Die Enumeration »LineCap«

LineCap-Member Beschreibung
AnchorMask Prüft, ob es sich um einen Anchor handelt.
ArrowAnchor Pfeilförmiges Ankerende
Custom Benutzerdefiniertes Linienende
DiamondAnchor Rautenförmiges Ankerende
Flat Abgeflaches Linienende
NoAnchor Kein Anker
Round Rundes Linienende
RoundAnchor Rundes Ankerende
Square Quadratisches Linienende
SquareAnchor Quadratisches Ankerlinienende
Triangle Dreieckiges Linienende

Das folgende Beispielprogramm demonstriert, wie sich die einzelnen Mitglieder von LineCap auf den Linienabschluss auswirken.

Abbildung
Hier klicken, um das Bild zu vergrößern

Abbildung 22.24   Die Linienenden, festgelegt mit »LineCap«


// --------------------------------------------------------------
// Beispiel: ...\Kapitel 22\Linienenden
// --------------------------------------------------------------
private void Form1_Paint(object sender, PaintEventArgs e) {
  Pen pen = new Pen(Color.Blue, 15);
  Brush brush = new SolidBrush(Color.Black);
  Font font = new Font("Courier New", 10);
  foreach (LineCap lc in Enum.GetValues(typeof(LineCap))) {
    e.Graphics.DrawString(lc.ToString(), font,brush, 10, 10);
    // Linienenden festlegen
    pen.StartCap = lc;
    pen.EndCap   = lc;
    // Linie zeichnen
    e.Graphics.DrawLine(pen, 150, 20, 400, 20);
    // Koordinatenursprung verschieben
    e.Graphics.TranslateTransform(0, 30);
  }
}

Es bleibt noch ein Punkt zu erwähnen: die Einstellung LineCap.Custom. Dazu wird den Eigenschaften CustomStartCap und CustomEndCap des Pen-Objekts die Referenz auf ein CustomLineCap-Objekt übergeben, das die Linienenden über die passenden Übergabeparameter an den Konstruktor bestimmt.

Kombinationsmöglichkeiten

Wir sind am Ende der Beschreibung der Klassen Pen und Brush angelangt. Wenn Sie aufmerksam gefolgt sind, haben Sie feststellen können, dass sich beide Typen sehr schön kombinieren lassen, weil zwei der vier Konstruktoren von Pen als Übergabeargument den Typ Brush erwarten. Da eine geometrische Figur wie ein Ansichtsfenster auf die mit einem Brush gezeichnete Grundfläche wirkt, sind den Gestaltungsmöglichkeiten kaum kreative Grenzen gesetzt. Ich möchte Ihnen das an einem einfachen Beispiel zeigen, in dem mit der Klasse PathGradientBrush ein farblicher Übergang definiert wird, der einen Pfeil optisch reizvoll aussehen lässt.

Abbildung
Hier klicken, um das Bild zu vergrößern

Abbildung 22.25   Effektvoller Pfeil durch Kombination verschiedener Klassen


private void Form1_Paint(object sender, PaintEventArgs e) {
  // das Brush-Objekt festlegen
  GraphicsPath graphPath = new GraphicsPath();
  graphPath.AddRectangle(new Rectangle(0, 0, 400, 200));
  PathGradientBrush brush = new PathGradientBrush(graphPath);
  brush.CenterPoint = new Point(300, 100);
  brush.CenterColor = Color.White;
  brush.SurroundColors = new Color[]{Color.Black};
  // das Pen-Objekt definieren
  Pen pen = new Pen(brush, 100);
  pen.EndCap = LineCap.ArrowAnchor;
  // einen Pfeil in die Form zeichnen
  e.Graphics.DrawLine(pen,new Point(40, 100), new Point(400, 100));
}


Galileo Computing

22.3.3 Farbeinstellungen mit »Color«  toptop

Farben haben wir nicht nur in diesem, sondern auch schon in den vergangenen Kapiteln reichlich festgelegt. Wir haben uns dazu immer der Struktur Color bedient und eine der insgesamt 140 vordefinierten Konstanten daraus verwendet.

Wem diese Farbpalette nicht ausreicht, der kann auf eine der vier statischen Methoden FromArgb der Color-Struktur zurückgreifen und eine der über 16 Millionen Farben basierend auf dem Rot-, Grün- oder Blauanteil selbst festlegen:


public static Color FromArgb(int, int, int);

Das erste Argument beschreibt den Rotanteil, das zweite den grünen und das dritte den blauen Anteil. Den jeweiligen Argumenten kann ein Zahlenwert von 0 bis 255 übergeben werden. Dabei gilt, dass


Color.FromArgb(0, 0, 0);

der Farbe Schwarz entspricht und


Color.FromArgb(255, 255, 255);

der Farbe Weiß.

Mit einer überladenen Variante lässt sich ein Farbschema festlegen, das dem ARGB-Modell (Alpha-Rot-Grün-Blau) folgt. Der Alpha-Kanal legt in diesem die Transparenz einer Farbe fest. Dabei bedeutet 255, dass die Farbe vollständig decken soll, und 0, dass die Farbe 100  %ig durchsichtig ist:


public static Color FromArgb(int, int, int, int);

Der erste Parameter beschreibt den Alpha-Kanal, die anderen drei die Rot-, Grün- und Blauanteile.

Die drei Anteile Rot, Grün und Blau werden in den Eigenschaften R, G und B von Color festgehalten, der Wert des Alpha-Kanals in A. Alle sind vom Typ Byte.

Systemfarben ermitteln

Es wird etwas schwieriger, mit den Color-Farbeinstellungen zu arbeiten, wenn Sie auf die Systemfarben von Windows zurückgreifen wollen, da Sie nicht wissen können, wie der Anwender das Schema individuell eingestellt hat. In diesem Fall können Sie die Farben nicht statisch codieren, sondern müssen diese zur Laufzeit dynamisch ermitteln. Dazu dient die Klasse SystemColors, die sich dem Namespace System.Drawing eingliedert.

In dieser Klasse ist eine stattliche Anzahl statischer Eigenschaften vordefiniert, die als Rückgabewert den Typ Color liefern. Mit der Eigenschaft Window können Sie zum Beispiel die aktuelle Hintergrundfarbe des Clientbereichs eines Fensters feststellen. Das ist dann nicht die, die über die Eigenschaft BackColor zugewiesen worden ist, sondern diejenige, deren Schema aufgrund der Einstellung im Eigenschaftsfenster des Desktops aktuell der Standard ist.

 << zurück
  
  Zum Katalog
Zum Katalog: Visual C# 2005
Visual C# 2005
bestellen
 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Buchtipps
Zum Katalog: Fortgeschrittene Programmierung mit Visual C# 2005






 Fortgeschrittene
 Programmierung
 mit Visual C# 2005


Zum Katalog: Einstieg in Visual C# 2005






 Einstieg in
 Visual C# 2005


Zum Katalog: Einstieg in Visual Basic 2005






 Einstieg in
 Visual Basic 2005


Zum Katalog: Visual Basic 2005






 Visual Basic 2005


Zum Katalog: Java ist auch eine Insel






 Java ist auch eine
 Insel


Zum Katalog: Konzepte und Lösungen für Microsoft-Netzwerke






 Konzepte und
 Lösungen für
 Microsoft-Netzwerke


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo








Copyright © Galileo Press 2006
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Galileo Computing]

Galileo Press, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de